<?php
// 应用公共文件

use app\MyException;
use think\response\Json;
use think\Exception;
use think\facade\Cache;
use app\model\SystemConfigModel;

/**
 * @param  mixed  $data
 * @param  string  $msg
 * @param  int  $code
 *
 * @return Json
 */
function success(mixed $data = [], string $msg = 'success', int $code = 0): Json
{
    $result = [
        'code'    => $code,
        'message' => $msg,
        'data'    => $data,
    ];

    return json($result);
}


/**
 * @param  mixed  $data
 * @param  string  $msg
 * @param  int  $code
 *
 * @return Json
 */
function error(string $msg = 'fail', int $code = 1, mixed $data = []): Json
{
    $result['msg'] = ! empty($msg) ? $msg : 'fail';
    $result        = [
        'code'    => $code,
        'message' => $msg,
        'data'    => $data,
    ];

    return json($result);
}


/**
 * 自定义异常
 *
 * @param  string  $msg
 * @param  int  $code
 *
 * @return MyException
 */
function myException(string $msg, int $code = 1): MyException
{
    throw new MyException($msg, $code);
}


/**
 * 抛出异常
 *
 * @param $msg
 *
 * @return void
 */
function exception($msg): void
{
    throw new Exception($msg);
}


/**
 * 获取项目绝对路径
 */
function getDirectory(): string
{
    return app()->getRootPath();
}


/**
 * 获取系统配置
 */
function getConfigs(string $key): mixed
{
    if (empty($key)) {
        \myException('查询key缺失');
    }

    $keys = explode('.', $key);
    $num = count($keys);

    if ($num < 1 || $num > 2) {
        \myException('key错误');
    }

    $tag = getDirectory().'_systemconfig_';

    // 获取主配置 sign
    $mainSign = $keys[0];

    // 从缓存中获取配置数据
    if (Cache::has($tag.$mainSign)) {
        $configData = Cache::get($tag.$mainSign);
    } else {
        // 缓存未命中，从数据库查询
        $config = (new SystemConfigModel())->getOne([['sign', '=', $mainSign]]);
        if (empty($config)) {
            \myException('配置不存在');
        }

        // 解析配置内容并缓存
        $configData = jsonToArray($config['content']);
        Cache::tag($tag)->set($tag.$mainSign, $configData);
    }

    // 如果是一级配置，直接返回
    if ($num === 1) {
        return $configData;
    }

    // 查找二级配置
    $subSign = $keys[1];
    $index = array_search($subSign, array_column($configData, 'sign'));

    if ($index === false) {
        \myException('配置不存在');
    }

    return $configData[$index]['value'];
}


/**
 * 系统加密方法
 *
 * @param  string  $data  要加密的字符串
 * @param  string  $key  加密密钥
 * @param  int  $expire  过期时间 单位 秒
 *
 * @return string
 */
function think_encrypt(string $data, string $key = '', int $expire = 0): string
{
    $key  = md5(empty($key) ? '123' : $key);
    $data = base64_encode($data);
    $x    = 0;
    $len  = strlen($data);
    $l    = strlen($key);
    $char = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l) {
            $x = 0;
        }
        $char .= substr($key, $x, 1);
        $x++;
    }

    $str = sprintf('%010d', $expire ? $expire + time() : 0);

    for ($i = 0; $i < $len; $i++) {
        $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1))) % 256);
    }

    $str = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($str));

    return strtoupper(md5($str)).$str;
}


/**
 * 系统解密方法
 *
 * @param  string  $data  要解密的字符串 （必须是think_encrypt方法加密的字符串）
 * @param  string  $key  加密密钥
 *
 * @return string
 */
function think_decrypt(string $data, string $key = ''): string
{
    $key  = md5(empty($key) ? '123' : $key);
    $data = substr($data, 32);
    $data = str_replace(['-', '_'], ['+', '/'], $data);
    $mod4 = strlen($data) % 4;
    if ($mod4) {
        $data .= substr('====', $mod4);
    }
    $data   = base64_decode($data);
    $expire = substr($data, 0, 10);
    $data   = substr($data, 10);

    if ($expire > 0 && $expire < time()) {
        return '';
    }
    $x    = 0;
    $len  = strlen($data);
    $l    = strlen($key);
    $char = $str = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l) {
            $x = 0;
        }
        $char .= substr($key, $x, 1);
        $x++;
    }

    for ($i = 0; $i < $len; $i++) {
        if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
            $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
        } else {
            $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
        }
    }

    return base64_decode($str);
}


/**
 * JSON转数组
 *
 * @param  string  $data
 *
 * @return array
 */
function jsonToArray(string $data): array
{
    return json_decode($data, true);
}


/**
 * 数组转JSON
 *
 * @param  array  $data
 *
 * @return string
 */
function arrayToJson(array $data): string
{
    return json_encode($data, JSON_UNESCAPED_UNICODE );
}